﻿using System;
using Microsoft.Xna.Framework;

namespace ThreeDWorld
{
    public static class BoundsHelper
    {
        public static BoundingBox Transform(BoundingBox b, Matrix matrix)
        {
            BoundingBox t = new BoundingBox(matrix.Translation, matrix.Translation);

            t.Min.X += (matrix.M11 < 0) ? matrix.M11 * b.Max.X : matrix.M11 * b.Min.X;
            t.Min.X += (matrix.M21 < 0) ? matrix.M21 * b.Max.Y : matrix.M21 * b.Min.Y;
            t.Min.X += (matrix.M31 < 0) ? matrix.M31 * b.Max.Z : matrix.M31 * b.Min.Z;
            t.Max.X += (matrix.M11 > 0) ? matrix.M11 * b.Max.X : matrix.M11 * b.Min.X;
            t.Max.X += (matrix.M21 > 0) ? matrix.M21 * b.Max.Y : matrix.M21 * b.Min.Y;
            t.Max.X += (matrix.M31 > 0) ? matrix.M31 * b.Max.Z : matrix.M31 * b.Min.Z;

            t.Min.Y += (matrix.M12 < 0) ? matrix.M12 * b.Max.X : matrix.M12 * b.Min.X;
            t.Min.Y += (matrix.M22 < 0) ? matrix.M22 * b.Max.Y : matrix.M22 * b.Min.Y;
            t.Min.Y += (matrix.M32 < 0) ? matrix.M32 * b.Max.Z : matrix.M32 * b.Min.Z;
            t.Max.Y += (matrix.M12 > 0) ? matrix.M12 * b.Max.X : matrix.M12 * b.Min.X;
            t.Max.Y += (matrix.M22 > 0) ? matrix.M22 * b.Max.Y : matrix.M22 * b.Min.Y;
            t.Max.Y += (matrix.M32 > 0) ? matrix.M32 * b.Max.Z : matrix.M32 * b.Min.Z;

            t.Min.Z += (matrix.M13 < 0) ? matrix.M13 * b.Max.X : matrix.M13 * b.Min.X;
            t.Min.Z += (matrix.M23 < 0) ? matrix.M23 * b.Max.Y : matrix.M23 * b.Min.Y;
            t.Min.Z += (matrix.M33 < 0) ? matrix.M33 * b.Max.Z : matrix.M33 * b.Min.Z;
            t.Max.Z += (matrix.M13 > 0) ? matrix.M13 * b.Max.X : matrix.M13 * b.Min.X;
            t.Max.Z += (matrix.M23 > 0) ? matrix.M23 * b.Max.Y : matrix.M23 * b.Min.Y;
            t.Max.Z += (matrix.M33 > 0) ? matrix.M33 * b.Max.Z : matrix.M33 * b.Min.Z;

            return t;
        }

        public static BoundingBox Transform(BoundingBox b, Vector3 scale, Vector3 translation)
        {
            return new BoundingBox(b.Min * scale + translation, b.Max * scale + translation);
        }

        public static BoundingBox Buffer(BoundingBox bounds, float b)
        {
            Vector3 d = new Vector3(b, b, b);

            return new BoundingBox(bounds.Min - d, bounds.Max + d);
        }

        public static bool Collide(BoundingBox a, BoundingBox b, out int axis, out float direction, out float translation)
        {
            float d;

            axis = -1;
            direction = 0;
            translation = 0;

            d = a.Max.X - b.Min.X;
            if (d < 0)
            {
                return false;
            }
            {
                translation = d;
                direction = -1;
                axis = 0;
            }

            d = b.Max.X - a.Min.X;
            if (d < 0)
            {
                return false;
            }
            if (d < translation) 
            {
                translation = d;
                direction = 1;
                axis = 0;
            }

            d = a.Max.Y - b.Min.Y;
            if (d < 0)
            {
                return false;
            }
            if(d < translation)
            {
                translation = d;
                direction = -1;
                axis = 1;
            }

            d = b.Max.Y - a.Min.Y;
            if (d < 0)
            {
                return false;
            }
            if (d < translation)
            {
                translation = d;
                direction = 1;
                axis = 1;
            }

            d = a.Max.Z - b.Min.Z;
            if (d < 0)
            {
                return false;
            }
            if (d < translation)
            {
                translation = d;
                direction = -1;
                axis = 2;
            }

            d = b.Max.Z - a.Min.Z;
            if (d < 0)
            {
                return false;
            }
            if (d < translation)
            {
                translation = d;
                direction = 1;
                axis = 2;
            }

            return true;
        }
    }
}
